package com.silky.officeline.task;

import com.silky.common.bean.DataSourceConfig;
import com.silky.common.bean.MultiLevelJoinConfig;
import com.silky.common.bean.NodeConfig;
import com.silky.common.constant.IConstant;
import com.silky.common.service.NodeService;
import com.silky.common.utils.LoadDataSource;
import com.silky.common.utils.PageList;
import com.silky.common.utils.ParameterUtils;
import com.silky.common.utils.YamlConfigUtil;
import com.silky.officeline.thread.MultiLevelSingleThread;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

/**
 *  多级联表查询任务
 */
@Slf4j
public class MultiLevelJoinTask {
    public static void main(String[] args) throws Exception {
        //检查参数
        Map<String,String> params = ParameterUtils.makeParameterMap(args);
        if(!params.containsKey(IConstant.DATA_SOURCE_YML)||!params.containsKey(IConstant.TASK_YML)){
            printUseage();
            return;
        }
        if(StringUtils.isEmpty(params.get(IConstant.DATA_SOURCE_YML))||StringUtils.isEmpty(params.get(IConstant.TASK_YML))){
            printUseage();
            return;
        }
        DataSourceConfig dataSourceConfig = LoadDataSource.loadDataSource(params.get(IConstant.DATA_SOURCE_YML));
        MultiLevelJoinConfig multiLevelJoinConfig = new MultiLevelJoinConfig();
        YamlConfigUtil.loadYamlIntoBean(params.get(IConstant.TASK_YML),multiLevelJoinConfig);
        MultiLevelJoinTask multiLevelJoinTask = new MultiLevelJoinTask();
        multiLevelJoinTask.runTask(dataSourceConfig,multiLevelJoinConfig);
    }

    /**
     *  执行任务
     * @param dataSourceConfig
     * @param multiLevelJoinConfig
     */
    private void runTask(DataSourceConfig dataSourceConfig, MultiLevelJoinConfig multiLevelJoinConfig) throws Exception {
        //循环初始化MultiLevelJoinConfig 中的分页列表
        Long startTime = System.currentTimeMillis();
        System.out.println("开始执行任务,时间戳:"+startTime);

        PageList initPageList = calculationFirstLevelPageList(dataSourceConfig,multiLevelJoinConfig);
        Thread[] threads = new Thread[multiLevelJoinConfig.getThreadNum()];
        CountDownLatch countDownLatch = new CountDownLatch(initPageList.size());
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(new MultiLevelSingleThread(dataSourceConfig,multiLevelJoinConfig,initPageList,countDownLatch,0));
            threads[i].start();
        }
        System.out.println("等待所有子线程处理完毕");
        //等待子线程处理完毕
        countDownLatch.await();
        long endTime = System.currentTimeMillis();
        System.out.println("结束执行任务,时间戳:"+endTime);
        System.out.println("所有子线程处理完毕,耗费时间:"+(endTime - startTime)/1000/60+"分钟");
        log.info("所有子线程处理完毕");
    }

    /**
     * 计算第一级页数列表
     *
     * @param dataSourceConfig
     * @param multiLevelJoinConfig
     * @return
     */
    private PageList calculationFirstLevelPageList(DataSourceConfig dataSourceConfig, MultiLevelJoinConfig multiLevelJoinConfig) throws Exception {
        PageList pageList = new PageList();
        if(multiLevelJoinConfig.getNodes()==null||multiLevelJoinConfig.getNodes().size()==0)
            throw new Exception("尚未定义节点!");
        //第一层必须为Single
        NodeConfig nodeConfig = multiLevelJoinConfig.getNodes().get(0);
        if(!nodeConfig.getType().equals(IConstant.NODE_TYPE_SINGLE)) {
            throw new Exception("第一层必须为Single!");
        }
        NodeService nodeService = new NodeService(dataSourceConfig);
        //先查询记录数
        long totalCount = 0;
        totalCount = nodeService.getCount(nodeConfig);
        log.info("总记录数:{}", totalCount);
        List<Long> pageList1 = nodeService.splitOffset(totalCount, nodeConfig.getBatchSize());
        pageList.init(pageList1);
        return pageList;
    }

    /**
     * 打印使用方法
     */
    private static void printUseage() {
        log.info("Useage: java -cp xxx.jar cn.ccccltd.biz.historydata.task.MultiLevelJoinTask  -dsyml /xxx/xx/datasource.yml -taskyml /xxx/xxx/task.yml");
    }
}
